package state


import "binchunk"
import ."api"


// 对于某个Upvalue来说，对它的任何改动都必须反映在其它该Upvalue可见的地方
// 另外，当嵌套函数执行时，外围函数的局部变量有可能已经退出作用域了
// 为了应对这些情况，我们需要增加一个间接层
// 使用Upvalue结构体来封装Upvalue
type upvalue struct {

	val *luaValue

}


// 对应Lua语言层面的
type closure struct {

	proto	*binchunk.Prototype		// Lua函数原型

	goFunc	GoFunction				// Go闭包

	// 闭包要捕获外部函数的局部变量，就必须有地方来存放这些变量
	upvals	[]*upvalue			// Upvalue

}


// 创建Lua闭包
func newLuaClosure(proto *binchunk.Prototype) *closure {

	c := &closure{proto: proto}

	// Lua闭包捕获的Upvalue数量已经由编译器计算好了
	// 我们在创建Lua闭包时预先分配好空间即可
	if nUpvals := len(proto.Upvalues); nUpvals > 0 {

		c.upvals = make([]*upvalue, nUpvals)

	}

	return c
}


// 创建Go闭包
func newGoClosure(f GoFunction, nUpvals int) *closure {

	c := &closure{goFunc: f}

	// 不仅Lua闭包可以捕获Upvalue，Go闭包也可以捕获Upvalue
	// 与Lua闭包不同的是，我们需要在创建Go闭包时明确指定Upvalue的数量
	if nUpvals > 0 {

		c.upvals = make([]*upvalue, nUpvals)

	}

	return c
}